package org.liaohailong.library.widget.wheelview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import org.liaohailong.library.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Author: liaohailong
 * Date: 2022/8/20
 * Time: 8:13
 * Description: 列表选择器
 **/
public class WheelView extends FrameLayout {
    private static final String TAG = "WheelView";

    private void log(@NonNull String msg, Object... args) {
        String format = String.format(msg, args);
        Log.i(TAG, format);
    }

    private final RecyclerView mListView;
    private final Adapter mAdapter = new Adapter();


    // 配置属性
    private int mItemHeight; // 单个条目固定高度
    private int mItemOffset; // 上下偏移值，用来显示空白条目
    private int mTextSize = 16; // 文本字体大小
    private int mTextColorDefault = Color.WHITE; // 文本默认颜色
    private int mTextColorSelected = Color.WHITE; // 文本选中颜色
    private Drawable mSelectBackground; // 选中区域的显示内容

    // 选中区域
    private final Rect mSelectRect = new Rect();

    private int mScrollY = 0;
    private int mLastSelectPos = 0;

    public WheelView(@NonNull Context context) {
        this(context, null);
    }

    public WheelView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WheelView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WheelView);
        mItemHeight = a.getDimensionPixelSize(R.styleable.WheelView_item_height, mItemHeight);
        mItemOffset = a.getInteger(R.styleable.WheelView_item_offset, mItemOffset);
        mTextSize = a.getDimensionPixelSize(R.styleable.WheelView_text_size, mTextSize);
        mTextColorDefault = a.getColor(R.styleable.WheelView_text_color_default, mTextColorDefault);
        mTextColorSelected = a.getColor(R.styleable.WheelView_text_color_selected, mTextColorSelected);
        mSelectBackground = a.getDrawable(R.styleable.WheelView_select_background);

        a.recycle();


        // 内部添加一个RecyclerView来显示内容
        mListView = new RecyclerView(context);
        mListView.setLayoutManager(new LinearLayoutManager(context));
        mListView.setHasFixedSize(true); // 固定itemHeight，无需反复测量
        mListView.setAdapter(mAdapter);
        mListView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
//                log("onScrollStateChanged newState: %d", newState);

                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    // 手动拖动，停止矫正动画

                } else if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
                    // smoothScrollToPosition 等接口移动

                } else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    log("RecyclerView.SCROLL_STATE_IDLE scrollY: %d", mScrollY);
                    // 手动复位
                    int position = adjustPosition(mScrollY, true);
                    // 回调选中
                    performSelect(position);
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                mScrollY += dy;
                log("onScrolled scrollY: %d", mScrollY);
                performTextSelectedUi(mScrollY);
            }
        });

        addView(mListView);
    }

    /**
     * 矫正选中item的位置，摆放到中间去
     *
     * @param scrollY  当前列表滑动距离y
     * @param scrollBy 是否矫正位置
     * @return 当前选中的item的下标
     */
    private int adjustPosition(int scrollY, boolean scrollBy) {
        int offsetDy = scrollY % mItemHeight; // 当前中间的item偏移距离
        int selectPos = scrollY / mItemHeight; // 当前滑动过多少个item
        int limit = mItemHeight / 2;
        RecyclerView.Adapter<?> adapter = mListView.getAdapter();
        if (adapter == null) {
            return 0;
        }

        int dy = 0;
        if (offsetDy > limit) {
            // 展示下一个
            selectPos++;
            dy = mItemHeight - offsetDy;
        } else {
            // 展示当前
            dy = -offsetDy;
        }

//        log("selectPos : %d", selectPos);

        if (scrollBy) {
            mListView.smoothScrollBy(0, dy);
        }

        return selectPos;
    }

    private void performSelect(int position) {
        if (mLastSelectPos == position) return;
        mLastSelectPos = position;

        Adapter adapter = (Adapter) mListView.getAdapter();
        if (adapter != null)
            adapter.onClick(position);
    }

    private void performTextSelectedUi(int scrollY) {
        LinearLayoutManager layoutManager = (LinearLayoutManager) mListView.getLayoutManager();
        if (layoutManager == null) return;

        int currentPos = adjustPosition(scrollY, false);

        // 注意添加上下偏移值
        currentPos += mItemOffset;

        int firstPos = layoutManager.findFirstVisibleItemPosition();
        int lastPos = layoutManager.findLastVisibleItemPosition();
        for (int i = firstPos; i <= lastPos; i++) {
            View view = layoutManager.findViewByPosition(i);
            TextView textView = (TextView) view;
            if (textView == null) continue;

            // 动态变换颜色，提升用户体验感
            if (currentPos == i)
                textView.setTextColor(mTextColorSelected);
            else
                textView.setTextColor(mTextColorDefault);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        // 确定自身宽度 match_parent
        if (widthMode != MeasureSpec.EXACTLY) {
            widthSize = getSuggestedMinimumWidth();
            widthMode = MeasureSpec.EXACTLY;
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
        }

        // 确定自身大小
        // width = match parent
        // height = itemHeight * (offset*2 + 1)
        int height = mItemHeight * (mItemOffset * 2 + 1);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        // 测量 RecyclerView
        measureChildWithMargins(mListView, widthMeasureSpec, 0, heightMeasureSpec, 0);

        setMeasuredDimension(widthSize, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 设置中心选中区域
        mSelectRect.set(0, 0, w, mItemHeight);
        // 移动到中间
        int dy = h / 2 - mSelectRect.height() / 2;
        mSelectRect.offset(0, dy);
    }


    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);

        // 一个阴影遮罩
        if (mSelectBackground != null) {
            int bgWith = mSelectBackground.getIntrinsicWidth();
            int bgHeight = mSelectBackground.getIntrinsicHeight();
            if (bgWith <= 0 || bgHeight <= 0) {
                mSelectBackground.setBounds(0, 0, getMeasuredWidth(), mItemHeight);
            }
            canvas.save();
            canvas.translate(mSelectRect.left, mSelectRect.top);
            mSelectBackground.draw(canvas);
            canvas.restore();
        }

    }

    public void setPickRectBackground(Drawable mPickRectBackground) {
        this.mSelectBackground = mPickRectBackground;
        invalidate();
    }

    /**
     * 设置WheelView的内容，并刷新ui
     *
     * @param data     选择列表的内容
     * @param position 默认选中的位置
     * @param callback 选中操作回调
     */
    public void show(@NonNull List<Entity> data,
                     int position,
                     @NonNull Callback callback) {


        for (int i = 0; i < mItemOffset; i++) {
            data.add(0, new Entity("", null)); // 首部添加一个空数据
        }
        for (int i = 0; i < mItemOffset; i++) {
            data.add(new Entity("", null)); // 尾部添加一个空数据
        }

        mAdapter.setData(data);
        mAdapter.setCallback(callback);

        mListView.post(() -> {
            // 重新设置数据，需要获取当前的滑动距离和位置
            mScrollY = getListViewScrollY();
            mLastSelectPos = adjustPosition(mScrollY, false);

            // 移动到指定位置
            int targetPos = Math.max(0, position);
            targetPos = Math.min(data.size() - 1, targetPos);

            scrollToPosition(targetPos);
            mLastSelectPos = targetPos;
            mAdapter.onClick(targetPos);

            performTextSelectedUi(mScrollY);
            log("show scrollY: %d", mScrollY);
        });
    }

    private void scrollToPosition(int targetPos) {
        if (mLastSelectPos != targetPos) {
            int offset = targetPos - mLastSelectPos;
            offset *= mItemHeight;
            mListView.smoothScrollBy(0, offset);
        }
    }

    private int getListViewScrollY() {
        if (mListView == null) {
            return 0;
        }
        LinearLayoutManager layoutManager = (LinearLayoutManager) mListView.getLayoutManager();
        if (layoutManager == null) {
            return 0;
        }

        int firstPos = layoutManager.findFirstVisibleItemPosition();
        int scrollY = mItemHeight * firstPos;
        View firstView = layoutManager.findViewByPosition(firstPos);
        if (firstView == null) {
            return scrollY;
        }
        return scrollY + firstView.getTop();
    }


    private final class Adapter extends RecyclerView.Adapter<ViewHolder> {

        private final List<Entity> dataList = new ArrayList<>();
        private Callback callback;

        private void setData(@NonNull List<Entity> data) {
            dataList.clear();
            dataList.addAll(data);
            notifyDataSetChanged();
        }

        public void setCallback(Callback callback) {
            this.callback = callback;
        }

        public void onClick(int position) {
            if (callback != null) {
                int size = dataList.size();
                Entity entity = dataList.get((position + mItemOffset) % size);
                callback.onSelectChanged(entity, position);
            }
        }

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            TextView textView = new TextView(parent.getContext());
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
            textView.setTextColor(mTextColorDefault);


            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, mItemHeight);
            textView.setLayoutParams(lp);
            return new ViewHolder(textView);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            TextView textView = (TextView) holder.itemView;
            textView.setText(dataList.get(position).getTitle());

            if (mLastSelectPos == position) {
                textView.setTextColor(mTextColorSelected);
            } else {
                textView.setTextColor(mTextColorDefault);
            }

            // 给item添加点击选中的功能
            textView.setOnClickListener(v -> {
                int adapterPosition = holder.getAdapterPosition();
                adapterPosition -= mItemOffset;
                scrollToPosition(adapterPosition);
                performSelect(adapterPosition);
            });

//            // 测试颜色
//            if (position % 2 == 0)
//                textView.setBackgroundColor(0XFF4A1C66);
//            else
//                textView.setBackgroundColor(0XFF908766);
        }

        @Override
        public int getItemCount() {
            return dataList.size();
        }
    }


    private static final class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    public static class Entity {
        private final String title;
        private final Object tag;


        public Entity(String title, Object tag) {
            this.title = title;
            this.tag = tag;
        }


        public String getTitle() {
            return title;
        }

        public Object getTag() {
            return tag;
        }
    }


    public interface Callback {
        void onSelectChanged(@NonNull Entity entity, int position);
    }
}
